﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HelloWorld.Code.Util;

namespace HelloWorld.Code.DataAccess
{
    [MetadataType(typeof(UserMetaData))]
    public partial class User : IValidatableObject
    {
        /// <summary>
        /// Helper property used to store the URL referrer of the current page. Needed for the 'Go back to list' functionality.
        /// </summary>
        public string UrlReferrer { get; set; }

        /// <summary>
        /// Get a list that contains the available user roles.
        /// </summary>
        public IEnumerable<SelectListItem> UserRolesList
        {
            get
            {
                return (new[]
                            {
                                new SelectListItem
                                    {
                                        Selected = (UserRoleId == 0),
                                        Text = "Select...",
                                        Value = string.Empty
                                    }
                            }).Union(CacheManager.GetUserRoles(HttpContext.Current.Request.HttpMethod == "POST").
                                         Select(c => new SelectListItem
                                         {
                                             Selected = (c.UserRoleId == UserRoleId),
                                             Text = c.UserRoleName,
                                             Value = c.UserRoleId.ToString(CultureInfo.InvariantCulture)
                                         }));
            }
        }

        /// <summary>
        /// Saves the model using the repository and unit of work.
        /// </summary>
        public void Save()
        {
            using (var unitOfWork = new UnitOfWork())
            {
                var repository = unitOfWork.GetUserRepository;

                if (UserId == 0)
                    repository.Insert(this);
                else
                    repository.Update(this);

                unitOfWork.Save();                
            }
        }

        /// <summary>
        /// Validates that the username is unique among all users.
        /// </summary>
        /// <param name="validationContext"></param>
        /// <returns></returns>
        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            using (var unitOfWork = new UnitOfWork())
            {
                var repository = unitOfWork.GetUserRepository;
                var existingUser = repository.Search(u => u.UserId != UserId &&
                        string.Compare(u.Username, Username, StringComparison.CurrentCultureIgnoreCase) == 0, null, null);
                
                if(existingUser.Count > 0)
                    yield return new ValidationResult("Username already taken. Please choose another username.", new[] { "Username" });
            }
        }
    }

    public class UserMetaData
    {
        [Required(ErrorMessage = "Required")]
        [StringLength(100, MinimumLength = 3, ErrorMessage = "The first name must be a string of at least 3 characters and at most 100 characters")]
        [Display(Name = "First Name")]
        public string FirstName { get; set; }

        [Required(ErrorMessage = "Required")]
        [StringLength(100, MinimumLength = 3, ErrorMessage = "The last name must be a string of at least 3 characters and at most 100 characters")]
        [Display(Name = "Last Name")]
        public string LastName { get; set; }

        [Required(ErrorMessage = "Required")]
        [StringLength(100, ErrorMessage = "The e-mail can't have more than 100 characters")]
        [RegularExpression(@"^\w+([-+.]*[\w-]+)*@(\w+([-.]?\w+)){1,}\.\w{2,4}$", ErrorMessage = "Invalid e-mail")]
        [Display(Name = "E-mail")]
        public string Email { get; set; }

        [Required(ErrorMessage = "Required")]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "The username must be a string of at least 3 characters and at most 50 characters")]
        public string Username { get; set; }

        [Required(ErrorMessage = "Required")]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "The password must be a string of at least 3 characters and at most 50 characters")]
        public string Password { get; set; }

        [Required(ErrorMessage = "Required")]
        [Range(1, 2, ErrorMessage = "Required")]
        [Display(Name = "User role")]
        public int UserRoleId { get; set; }
    }
}